﻿//Synthetic.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Derivatives
{
	using System;
	using System.Collections.Generic;

	using StockSharp.BusinessEntities;

	/// <summary>
	/// Построитель синтетических позиций.
	/// </summary>
	public class Synthetic
	{
		private readonly Security _security;

		/// <summary>
		/// Создать <see cref="Synthetic"/>.
		/// </summary>
		/// <param name="security">Инструмент (опцион или базовый актив).</param>
		public Synthetic(Security security)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			_security = security;
		}

		private Security Option
		{
			get
			{
				_security.CheckOption();
				return _security;
			}
		}

		/// <summary>
		/// Получить синтетическую позицию для покупки опциона.
		/// </summary>
		/// <returns>Синтетическая позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Buy()
		{
			return Position(OrderDirections.Buy);
		}

		/// <summary>
		/// Получить синтетическую позицию для продажи опциона.
		/// </summary>
		/// <returns>Синтетическая позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Sell()
		{
			return Position(OrderDirections.Sell);
		}

		/// <summary>
		/// Получить синтетическую позицию для опциона.
		/// </summary>
		/// <param name="direction">Направление основной позиции.</param>
		/// <returns>Синтетическая позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Position(OrderDirections direction)
		{
			var asset = Option.GetUnderlyingAsset();

			return new[]
			{
				new KeyValuePair<Security, OrderDirections>(asset, Option.OptionType == OptionTypes.Call ? direction : direction.Invert()),
				new KeyValuePair<Security, OrderDirections>(Option.GetOppositeOption(), direction)
			};
		}

		/// <summary>
		/// Получить опционную позицию для синтетической покупки базового актива.
		/// </summary>
		/// <param name="strike">Страйк.</param>
		/// <returns>Опционная позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Buy(decimal strike)
		{
			return Buy(strike, GetExpiryDate());
		}

		/// <summary>
		/// Получить опционную позицию для синтетической покупки базового актива.
		/// </summary>
		/// <param name="strike">Страйк.</param>
		/// <param name="expiryDate">Дата экспирации опциона.</param>
		/// <returns>Опционная позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Buy(decimal strike, DateTime expiryDate)
		{
			return Position(strike, expiryDate, OrderDirections.Buy);
		}

		/// <summary>
		/// Получить опционную позицию для синтетической продажи базового актива.
		/// </summary>
		/// <param name="strike">Страйк.</param>
		/// <returns>Опционная позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Sell(decimal strike)
		{
			return Sell(strike, GetExpiryDate());
		}

		/// <summary>
		/// Получить опционную позицию для синтетической продажи базового актива.
		/// </summary>
		/// <param name="strike">Страйк.</param>
		/// <param name="expiryDate">Дата экспирации опциона.</param>
		/// <returns>Опционная позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Sell(decimal strike, DateTime expiryDate)
		{
			return Position(strike, expiryDate, OrderDirections.Sell);
		}

		/// <summary>
		/// Получить опционную позицию для синтетического базового актива.
		/// </summary>
		/// <param name="strike">Страйк.</param>
		/// <param name="expiryDate">Дата экспирации опциона.</param>
		/// <param name="direction">Направление основной позиции.</param>
		/// <returns>Опционная позиция.</returns>
		public KeyValuePair<Security, OrderDirections>[] Position(decimal strike, DateTime expiryDate, OrderDirections direction)
		{
			var call = _security.GetCall(strike, expiryDate);
			var put = _security.GetPut(strike, expiryDate);

			return new[]
			{
				new KeyValuePair<Security, OrderDirections>(call, direction),
				new KeyValuePair<Security, OrderDirections>(put, direction.Invert())
			};
		}

		private DateTime GetExpiryDate()
		{
			if (_security.ExpiryDate == null)
				throw new InvalidOperationException("Инструмент не имеет информации о дате истечения.");

			return (DateTime)_security.ExpiryDate;
		}
	}
}